<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>SpringBoot面经 | 无人深空</title><meta name="keywords" content="SpringBoot"><meta name="author" content="zcm"><meta name="copyright" content="zcm"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="Spring Boot 面经1.Spring Boot 简介 什么是 Spring Boot  通过 Spring Boot，可以轻松地创建独立的、基于生产级别的 Spring 的应用程序 大多数 Spring Boot 应用程序只需要最少的 Spring 配置   为什么要用 Spring Boot  快速开发，快速整合，配置简化、内嵌服务容器    Spring Boot 的优缺点  优点 容">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringBoot面经">
<meta property="og:url" content="https://gitee.com/zcmmmm/zcmmmm/2022/10/27/SpringBoot%E9%9D%A2%E7%BB%8F/index.html">
<meta property="og:site_name" content="无人深空">
<meta property="og:description" content="Spring Boot 面经1.Spring Boot 简介 什么是 Spring Boot  通过 Spring Boot，可以轻松地创建独立的、基于生产级别的 Spring 的应用程序 大多数 Spring Boot 应用程序只需要最少的 Spring 配置   为什么要用 Spring Boot  快速开发，快速整合，配置简化、内嵌服务容器    Spring Boot 的优缺点  优点 容">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://study-record-images.oss-cn-beijing.aliyuncs.com/Java/Spring/Spring.jpg">
<meta property="article:published_time" content="2022-10-27T02:39:30.000Z">
<meta property="article:modified_time" content="2023-05-02T02:09:03.343Z">
<meta property="article:author" content="zcm">
<meta property="article:tag" content="SpringBoot">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://study-record-images.oss-cn-beijing.aliyuncs.com/Java/Spring/Spring.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://gitee.com/zcmmmm/zcmmmm/2022/10/27/SpringBoot%E9%9D%A2%E7%BB%8F/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":200},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#1f1f1f","position":"bottom-left"},
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'SpringBoot面经',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-05-02 10:09:03'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><link rel="stylesheet" href="/css/categories.css?v1"><link rel="stylesheet" href="/css/navigation.css?v1"><link rel="stylesheet" href="/css/custom.css?v1"><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://s2.loli.net/2022/09/22/36LN4kcjYOd9HT8.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">43</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">25</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">无人深空</a></span><div id="menus"></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div></div><div id="nav-right"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i></a></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">SpringBoot面经</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-10-27T02:39:30.000Z" title="发表于 2022-10-27 10:39:30">2022-10-27</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-05-02T02:09:03.343Z" title="更新于 2023-05-02 10:09:03">2023-05-02</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E9%9D%A2%E7%BB%8F/">面经</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Spring/">Spring</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">4.6k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>15分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="SpringBoot面经"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div><article class="post-content" id="article-container"><h2 id="Spring-Boot-面经"><a href="#Spring-Boot-面经" class="headerlink" title="Spring Boot 面经"></a>Spring Boot 面经</h2><h3 id="1-Spring-Boot-简介"><a href="#1-Spring-Boot-简介" class="headerlink" title="1.Spring Boot 简介"></a>1.Spring Boot 简介</h3><ol>
<li><p>什么是 Spring Boot</p>
<blockquote>
<p>通过 Spring Boot，可以轻松地创建独立的、基于生产级别的 Spring 的应用程序</p>
<p>大多数 Spring Boot 应用程序只需要最少的 Spring 配置</p>
</blockquote>
</li>
<li><p>为什么要用 Spring Boot</p>
<blockquote>
<p>快速开发，快速整合，配置简化、内嵌服务容器 </p>
</blockquote>
</li>
<li><p>Spring Boot 的优缺点</p>
<ul>
<li>优点<ul>
<li>容易上手，提升开发效率，为 Spring 开发提供一个更快、更简单的开发框架</li>
<li>开箱即用，远离繁琐的配置</li>
<li>提供了一系列大型项目通用的非业务性功能，例如：内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等</li>
<li>SpringBoot 总结就是使编码变简单、配置变简单、部署变简单、监控变简单等等</li>
</ul>
</li>
<li>缺点<ul>
<li>由于不用自己做的配置，报错时很难定位</li>
</ul>
</li>
</ul>
</li>
<li><p>Spring Boot 和 Spring Cloud 的区别</p>
<blockquote>
<p>Spring Boot 是快速开发的 Spring 框架</p>
<p>Spring Cloud 是完整的微服务框架</p>
<p>Spring Cloud 依赖于 Spring Boot</p>
</blockquote>
</li>
<li><p>Spring Boot 核心注解</p>
<blockquote>
<p>启动类上面的注解是 <code>@SpringBootApplication</code>，它也是 Spring Boot 的核心注解，主要组合包含了以下 3 个注解： </p>
</blockquote>
<ul>
<li><p><code>@SpringBootConfifiguration</code>：组合了 <code>@Confifiguration</code> 注解，实现配置文件的功能 </p>
</li>
<li><p><code>@EnableAutoConfifiguration</code>：打开自动配置的功能，也可以关闭某个自动配置的选项</p>
<blockquote>
<p>例如： java 关闭数据源自动配置功能： </p>
<p><code>@SpringBootApplication(exclude = &#123; DataSourceAutoConfiguration.class &#125;)</code> </p>
</blockquote>
</li>
<li><p><code>@ComponentScan</code>：Spring 组件扫描</p>
</li>
</ul>
</li>
<li><p>Spring Boot 2.X 有什么新特性？与 1.X 有什么区别？</p>
<ul>
<li>配置变更 </li>
<li>Spring Boot2 基于 Spring5 和 JDK8，Spring 1.x 用的是低版本</li>
<li>第三方类库升级 </li>
<li>响应式 Spring 编程支持 </li>
<li>2.x 配置中的中文可以直接读取，不用转码</li>
<li>HTTP&#x2F;2 支持 </li>
<li>配置属性绑定 </li>
<li>Actuator 的变化 </li>
<li>CacheManager 的变化</li>
</ul>
</li>
<li><p>运行 Spring Boot 有哪几种方式</p>
<ul>
<li>打包用命令或者放到容器中运行</li>
<li>用 Maven&#x2F; Gradle 插件运行 </li>
<li>直接执行 main 方法运行</li>
</ul>
</li>
<li><p>开启 Spring Boot 特性有哪几种方式</p>
<ul>
<li><p>继承 <code>spring-boot-starter-parent</code> 项目 </p>
<blockquote>
<p>新创建 Spring Boot 项目，默认都是有 parent 的，这个 parent 就是 <code>spring-boot-starter-parent</code></p>
<p><code>spring-boot-starter-parent</code> 主要有如下作用（主要是为了便于打包）</p>
</blockquote>
<ul>
<li>定义了 Java 编译版本为1.8</li>
<li>使用 UTF-8 格式编码</li>
<li>继承自 <code>spring-boot-dependencies</code>，这个里边定义了依赖的版本，也正是因为继承了这个依赖，所以在写依赖时才不需要写版本号</li>
<li>执行打包操作的配置</li>
<li>自动化的资源过滤</li>
<li>自动化的插件配置</li>
<li>针对 <code>application.properties</code> 和 <code>application.yml</code> 的资源过滤，包括通过 profile 定义的不同环境的配置文件，例如 <code>application-dev.properties</code> 和 <code>application-dev.yml</code></li>
</ul>
</li>
<li><p>导入 <code>spring-boot-dependencies</code> 项目依赖</p>
</li>
</ul>
</li>
<li><p>Spring Boot 读取配置的方式</p>
<blockquote>
<p>Spring Boot 可以通过 <code>@PropertySource、@Value、@Environment,、@ConfifigurationPropertie</code> 注解来绑定变量</p>
</blockquote>
</li>
<li><p>Spring Boot 自动配置原理</p>
<blockquote>
<p>Spring Boot 的启动类上的核心注解 <code>@SpringBootApplication</code> 注解主配置类，有了这个主配置类启动时就会为 Spring Boot 开启一个 <code>@EnableAutoConfiguration</code> 注解自动配置功能，该注解引入了 <code>AutoConfifigurationImportSelector</code>，该类中的方法会扫描所有存在 <code>META-INF/spring.factories</code> 的 jar 包</p>
<p><code>@EnableAutoConfiguration</code> 注解实现以下功能</p>
</blockquote>
<ul>
<li>从配置文件 <code>META_INF/Spring.factories</code> 加载可能用到的自动配置类</li>
<li>去重，并将 <code>exclude</code> 和 <code>excludeName</code> 属性携带的类排除</li>
<li>过滤，将满足条件 <code>@Conditional</code> 的自动配置类返回</li>
</ul>
</li>
<li><p>Spring Boot 配置加载顺序<strong>（以下配置文件有严格优先级）</strong></p>
<ul>
<li><p><code>.properties</code> 文件</p>
<blockquote>
<p>扁平化的 K-V 键值对格式</p>
</blockquote>
<figure class="highlight properties"><table><tr><td class="code"><pre><span class="line"><span class="attr">java.user.name</span> = <span class="string">zcm</span></span><br></pre></td></tr></table></figure>
</li>
<li><p><code>.yaml</code> 文件（建议使用）</p>
<blockquote>
<p>树形结构，可读性更强</p>
<p>配置有序，在一些特殊场景下需要该特性</p>
<p>支持数组类型</p>
<p>不支持 <code>@PropertySource</code> 注解导入自定义的 YAML 配置</p>
</blockquote>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">java:</span></span><br><span class="line">  <span class="attr">user:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">zcm</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>系统环境变量</p>
</li>
<li><p>命令行参数</p>
</li>
</ul>
</li>
<li><p>Spring Boot 核心配置文件是什么？</p>
<blockquote>
<p>单纯做 Spring Boot 开发，可能不太容易遇到 <code>bootstrap.properties</code> 配置文件</p>
<p>但是在结合 Spring Cloud 时，这个配置就会经常遇到了，特别是在需要加载一些远程配置文件的时候</p>
<p>Spring Boot 核心的两个配置文件：</p>
</blockquote>
<ul>
<li><p><code>bootstrap.yml</code> &#x2F; <code>bootstrap.properties</code></p>
<blockquote>
<p><code>boostrap</code> 由父 <code>ApplicationContext</code> 加载的，比 <code>applicaton</code> 优先加载，<strong>配置在应用程序上下文的引导阶段生效</strong></p>
<p>一般来说在 Spring Cloud 配置就会使用这个文件</p>
<p><strong>且 <code>boostrap</code> 里面的属性不能被覆盖</strong></p>
</blockquote>
</li>
<li><p>application（.yml或者·properties）：由ApplicatonContext加载，用于springboot项目的自动化配置。</p>
</li>
</ul>
</li>
<li><p>Spring Boot 中如何解决跨域问题</p>
<blockquote>
<p>跨域可以在前端通过 JSONP 来解决，但是 JSONP 只可以发送 GET 请求，无法发送其他类型的请求，在 RESTful 风格的应用中，就显得非常鸡肋</p>
<p>因此推荐在后端通过（CORS，Crossorigin resource sharing）来解决跨域问题</p>
<p>这种解决方案并非 Spring Boot 特有的，在传统的 SSM 框架中，就可以通过 CORS 来解决跨域问题，只不过之前是在 XML 文件中配置 CORS ，现在可以通过实现 <code>WebMvcConfifigurer</code> 接口然后重写 <code>addCorsMappings</code> 方法解决跨域问题</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CorsConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addCorsMappings</span><span class="params">(CorsRegistry registry)</span> &#123;</span><br><span class="line">		registry.addMapping(<span class="string">&quot;/**&quot;</span>)</span><br><span class="line">		.allowedOrigins(<span class="string">&quot;*&quot;</span>)</span><br><span class="line">		.allowCredentials(<span class="literal">true</span>)</span><br><span class="line">		.allowedMethods(<span class="string">&quot;GET&quot;</span>, <span class="string">&quot;POST&quot;</span>, <span class="string">&quot;PUT&quot;</span>, <span class="string">&quot;DELETE&quot;</span>, <span class="string">&quot;OPTIONS&quot;</span>)</span><br><span class="line">		.maxAge(<span class="number">3600</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>Spring Boot 性能如何优化</p>
<ul>
<li>如果项目比较大，类比较多，不使用 <code>@SpringBootApplication</code>，采用 <code>@Compoment</code> 指定扫包范围</li>
<li>在项目启动时设置 JVM 初始内存和最大内存相同 </li>
<li>将 Spring Boot 内置服务器由 tomcat 设置为 undertow</li>
</ul>
</li>
<li><p>Spring Boot 的特征</p>
<ul>
<li>创建独立的 Spring 应用程序 </li>
<li>直接嵌入 Tomcat、Jetty、Undertow（无需部署 WAR 文件） </li>
<li>提供固化的 <code>starter</code>依赖项，以简化构建配置 </li>
<li>尽可能自动配置 Spring 和 <code>3rd Party</code> 库 </li>
<li>提供可用于生产的功能，例如指标，运行状况检查和外部化配置 </li>
<li>完全没有代码生成，也不需要 XML 配置</li>
</ul>
</li>
<li><p>如何快速构建一个 Spring Boot 项目</p>
<ul>
<li>通过 <a target="_blank" rel="noopener" href="http://start.spring.io/">Web 界面</a>使用</li>
<li>通过 Spring Tool Suite 使用</li>
<li>通过 IntelliJ IDEA 使用</li>
<li>使用 Spring Boot CLI 使用</li>
</ul>
</li>
</ol>
<h3 id="2-Spring-Boot-多数据源"><a href="#2-Spring-Boot-多数据源" class="headerlink" title="2.Spring Boot 多数据源"></a>2.Spring Boot 多数据源</h3><ol>
<li><p>多数据源拆分思路</p>
<blockquote>
<p>先在 properties 配置文件中配置两个数据源，创建分包 mapper，使用 <code>@ConfifigurationProperties</code> 读取 <code>properties</code> 中的配置，使用 <code>@MapperScan</code> 注册到对应的 <code>mapper</code> 包中 </p>
</blockquote>
</li>
<li><p>多数据源事务管理</p>
<blockquote>
<p>有以下两种方法</p>
</blockquote>
<ul>
<li>在 service 层的 <code>@TransactionManager</code> 中使用 <code>transactionManager</code> 指定 <code>DataSourceConfifig</code> 中配置的事务 </li>
<li>使用 <code>jta-atomikos</code> 实现分布式事务管理</li>
</ul>
</li>
</ol>
<h3 id="3-Java-Config"><a href="#3-Java-Config" class="headerlink" title="3.Java Config"></a>3.Java Config</h3><blockquote>
<p>Spring Java Config 是 Spring 社区的产品，Spring3.0 引入，它提供了配置 SpringIOC 容器的纯 Java 方法</p>
<p>因此它有助于避免使用 XML 配置</p>
</blockquote>
<ul>
<li><p>Java Config 的优点</p>
<ul>
<li><p>面向对象的配置</p>
<blockquote>
<p>由于配置被定义为 Java Config 中的类，因此用户可以充分利用 Java 中的面向对象功能</p>
<p>一个配置类可以继承另一个，重写它的 @Bean 方法等</p>
</blockquote>
</li>
<li><p>减少或消除 XML 配置</p>
<blockquote>
<p><strong>基于依赖注入原则的外化配置的好处已被证明</strong></p>
<p>但是许多开发人员不希望在 XML 和 Java 之间来回切换</p>
<p>Java Config 为开发人员提供了一种纯 Java 方法来配置与 XML 配置概念相似的 Spring 容器</p>
<p>从技术角度来讲，只使用 Java Config 配置类来配置容器是可行的，但实际上很多人认为将 Java Config 与 XML 混合匹配是理想的</p>
</blockquote>
</li>
<li><p>类型安全和重构友好</p>
<blockquote>
<p>Java Config 提供了一种类型安全的方法来配置 Spring 容器</p>
<p>由于 Java5.0 对泛型的支持，现在可以按类型而不是按名称检索 bean，不需要任何强制转换或基于字符串的查找</p>
</blockquote>
</li>
</ul>
</li>
<li><p>常用的 Java Config</p>
<ul>
<li><p><code>@Configuration</code></p>
<blockquote>
<p>在类上添加此注解，表示这个类是配置类</p>
</blockquote>
</li>
<li><p><code>@ComponentScan</code></p>
<blockquote>
<p>在配置类上添加 <code>@Componentscan</code> 注解</p>
<p>该注解默认会扫描该类所在的包下所有的配置类，相当于之前的 <code>context:component-scan</code></p>
</blockquote>
</li>
<li><p><code>@Bean</code></p>
<blockquote>
<p>bean 的注入</p>
<p>相当于以前的<code>&lt;bean id=objectMapper class=org.codehaus.jackson.map.ObjectMapper/&gt;</code></p>
</blockquote>
</li>
<li><p><code>@EnableWebMvc</code></p>
<blockquote>
<p>相当于 xml 的 <code>&lt;mvcannotation-driven&gt;</code></p>
</blockquote>
</li>
<li><p><code>@ImportResource</code> </p>
<blockquote>
<p>相当于 xml 的 <code>&lt;importresource=applicationContext-cache.xml&gt;</code></p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h3 id="4-Spring-Boot-的安全性"><a href="#4-Spring-Boot-的安全性" class="headerlink" title="4.Spring Boot 的安全性"></a>4.Spring Boot 的安全性</h3><ol>
<li><p>如何保证 Spring Boot 的安全性</p>
<blockquote>
<p>为了实现 Spring Boot 的安全性，使用 <code>spring-boot-starter-security</code> 依赖项，并且必须添加安全配置（只需要很少的代码）</p>
<p>配置类将必须扩展 <code>WebsecurityConfigurerAdapter</code> 并覆盖其方法</p>
</blockquote>
</li>
<li><p>保护 Spring Boot 应用的方法</p>
<ul>
<li><p>在生产中使用 HTTPS </p>
</li>
<li><p>使用 Snyk 检查你的依赖关系 </p>
</li>
<li><p>升级到最新版本 </p>
</li>
<li><p>启用 CSRF 保护 </p>
<blockquote>
<p>CSRF 是跨站点请求伪造（Cross—Site Request Forgery）</p>
</blockquote>
</li>
<li><p>使用内容安全策略防止 XSS 攻击 </p>
<blockquote>
<p>跨站脚本攻击（Cross Site Scripting），为了不和层叠样式表（Cascading Style Sheets, CSS）的缩写混淆，故将跨站脚本攻击缩写为 XSS</p>
<p>恶意攻击者往 Web 页面里插入恶意的 Script 代码，当用户浏览该页之时，嵌入其中 Web 里面的 Script 代码会被执行，从而达到恶意攻击用户的目的</p>
</blockquote>
</li>
</ul>
</li>
<li><p>Spring Security 和 Shiro 各自的优缺点</p>
<blockquote>
<p>由于 Spring Boot 官方提供了大量的非常方便的开箱即用的 Starter，包括 Spring Security 的 Starter，使得在 Spring Boot 中使用 Spring Security 变得更加容易，甚至只需要添加一个依赖就可以保护所有的接口</p>
<p>所以如果是 Spring Boot 项目，一般选择 Spring Security</p>
<p>当然这只是一个建议的组合，单纯从技术上来说，无论怎么组合，都是没有问题的</p>
</blockquote>
<blockquote>
<p>Shiro 和 Spring Security 相比，主要有如下一些特点</p>
</blockquote>
<ul>
<li>Spring Security 是一个重量级的安全管理框架；Shiro 则是一个轻量级的安全管理框架</li>
<li>Spring Security 概念复杂，配置繁项；Shiro 概念简单、配置简单</li>
<li>Spring Security 功能强大；Shiro 功能简单</li>
</ul>
</li>
</ol>
<h3 id="5-Spring-Boot-监视器"><a href="#5-Spring-Boot-监视器" class="headerlink" title="5.Spring Boot 监视器"></a>5.Spring Boot 监视器</h3><ol>
<li><p>Spring Boot 中的监视器是什么</p>
<blockquote>
<p>Spring Boot Actuator 是 Spring 启动框架中的重要功能之一</p>
<p>Spring Boot 监视器可访问生产环境中正在运行的应用程序的当前状态</p>
<p>有几个指标必须在生产环境中进行检查和监控</p>
<p>即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息</p>
<p>监视器模块公开了一组可直接作为 HTTPURL 访问的 REST 端点来检查状态</p>
</blockquote>
</li>
<li><p>如何监视所有 Spring Boot 微服务</p>
<blockquote>
<p>Spring Boot 提供监视器端点以监控各个微服务的度量</p>
<p>这些端点对于获取有关应用程序的信息（如它们是否已启动）以及它们的组件（如数据库等）是否正常运行很有帮助</p>
<p>但是使用监视器的一个主要缺点或困难是：必须单独打开应用程序的知识点以了解其状态或健康状况</p>
<p>想象一下涉及 50 个应用程序的微服务，管理员必须打开所有 50 个应用程序的执行终端</p>
<p>为了处理这种情况，将使用<a target="_blank" rel="noopener" href="https://github.com/codecentric/spring-boot-admin">开源项目</a>。它建立在 Spring Boot Actuator 之上，提供了一个 Webul，能够可视化多个应用程序的度量</p>
</blockquote>
</li>
<li><p>配置监视器</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="6-Spring-Boot-Starter"><a href="#6-Spring-Boot-Starter" class="headerlink" title="6.Spring Boot Starter"></a>6.Spring Boot Starter</h3><ol>
<li><p>什么是 Starter</p>
<blockquote>
<p>Starter 并非什么新的技术点，基本上还是基于 Spring 已有功能来实现的</p>
<p>首先它提供了一个自动化配置类，一般命名为 <code>xxxAutoconfiguration</code>，在这个配置类中通过条件注解来决定一个配置是否生效（条件注解就是 Spring 中原本就有的）</p>
<p>然后它还会提供一系列的默认配置，也允许开发者根据实际情况自定义相关配置，然后通过类型安全的属性（<code>spring.factories</code>）注入这些配置属性，新注入的属性会代替掉默认属性</p>
<p>正因为如此很多第三方框架只需要引入依赖就可以直接使用了</p>
<p>开发者也可以自定义 Starter</p>
</blockquote>
<blockquote>
<p>可以理解成对依赖的一种合成，starter 会把一个或一套功能相关依赖都包含进来，避免手动依赖产生的包冲突问题，提高开发效率</p>
</blockquote>
</li>
<li><p>Spring Boot Starter 的工作原理</p>
<blockquote>
<p>Spring Boot 就是由各种 Starter 组合起来的，自己也可以开发 Starter </p>
<p>在 Spring Boot 启动时由 <code>@SpringBootApplication</code> 注解会自动去 maven 中读取每个 starter 中的 <code>spring.factories</code> 文件，该文件里配置了所有需要被创建 spring 容器中的 bean，并且进行自动配置把 bean 注入 <code>SpringContext</code> 中（ SpringContext 是 Spring 的配置文件）</p>
</blockquote>
</li>
</ol>
<h3 id="7-Spring-Boot-注解"><a href="#7-Spring-Boot-注解" class="headerlink" title="7.Spring Boot 注解"></a>7.Spring Boot 注解</h3><ol>
<li>启动类注解<ul>
<li>@SpringBootApplication（包含以下三个注解）<ul>
<li>@SpringBootConfiguration</li>
<li>@EnableAutoConfiguration</li>
<li>@ComponentScan</li>
</ul>
</li>
</ul>
</li>
<li>Controller 相关注解<ul>
<li>@Controller：控制器，处理 http 请求</li>
<li>@RestController</li>
<li>@RequestBody</li>
<li>@RequestMapping</li>
<li>@GetMapping</li>
<li>@PostMapping</li>
</ul>
</li>
<li>取请求参数值相关注解<ul>
<li>@PathVariable：获取 url 中的数据</li>
<li>@RequestParam：获取请求参数的值</li>
</ul>
</li>
<li>注入 bean 相关注解<ul>
<li>@Repository：DAO 层注解</li>
<li>@Service：Service 层注解</li>
<li>@Scope：作用域注解</li>
<li>@Entity：实体类注解</li>
<li>@Bean：产生一个 bean 的方法</li>
<li>@Autowired：自动导入</li>
<li>@Component</li>
</ul>
</li>
<li>事务注解<ul>
<li>@Transactional</li>
</ul>
</li>
<li>编写测试用例的注解<ul>
<li>@SpringBootTest</li>
</ul>
</li>
<li>异常处理相关注解<ul>
<li>@ControllerAdvice </li>
<li>@ExceptionHandler</li>
</ul>
</li>
<li>读取配置相关注解<ul>
<li>@PropertySource </li>
<li>@Value </li>
<li>@Environment </li>
<li>@ConfifigurationProperties</li>
</ul>
</li>
</ol>
<h3 id="其他细节"><a href="#其他细节" class="headerlink" title="其他细节"></a>其他细节</h3><ol>
<li><p>Spring Boot 支持哪些日志框架？推荐和默认的日志框架是哪个</p>
<blockquote>
<p>Spring Boot 支持 <code>Java Util Logging、Log4j2、Lockback</code> 作为日志框架</p>
<p>如果使用 Starters 启动器，Spring Boot 将使用 <code>Logback</code> 作为默认日志框架，但是不管是那种日志框架都支持将配置文件输出到控制台或者文件中</p>
</blockquote>
</li>
<li><p>Spring Boot 支持什么前端模板</p>
<blockquote>
<p>thymeleaf、freemarker、jsp</p>
<p>官方不推荐 JSP，会有限制 </p>
</blockquote>
</li>
<li><p>Spring Boot 需要独立的容器运行吗</p>
<blockquote>
<p>可以不需要，内置了 Tomcat &#x2F; Jetty 等容器</p>
</blockquote>
</li>
<li><p>Spring Boot 实现热部署有哪几种方式</p>
<blockquote>
<p>热部署即不用重新运行 Spring Boot 项目即可操作后台代码自动更新到正在运行的项目中</p>
<p>主要有以下两种方式</p>
</blockquote>
<ul>
<li>Spring Loaded</li>
<li>Spring-boot-devtools</li>
<li>Jrebel </li>
<li>模版热部署</li>
</ul>
</li>
<li><p>Spring Boot 事务的使用</p>
<blockquote>
<p>首先在启动类添加注解 <code>@EnableTransactionManagement</code> 开启事物，然后在 Service 方法上添加注解 <code>@Transactional</code> 便可</p>
</blockquote>
</li>
<li><p>如何在 Spring Boot 启动的时候运行一些特定的代码</p>
<blockquote>
<p>可以实现接口 <code>ApplicationRunner</code> 或者 <code>CommandLineRunner</code></p>
<p>这两个接口实现方式一样，它们都只提供了一个 run 方法 </p>
</blockquote>
</li>
<li><p>Async 异步调用方法</p>
<blockquote>
<p>只需要在方法上使用 <code>@Async</code> 注解即可实现方法的异步调用</p>
<p>注意：需要在启动类加入 <code>@EnableAsync</code> 使异步调用 <code>@Async</code> 注解生效</p>
</blockquote>
</li>
<li><p>Spring Boot 是否可以使用 XML 配置</p>
<blockquote>
<p>Spring Boot 推荐使用 Java 配置而非 XML 配置</p>
<p>但是 Spring Boot 中也可以使用 XML 配置，通过 <code>@ImportResource</code> 注解可以引入一个 XML 配置</p>
</blockquote>
</li>
<li><p>什么是 Spring Profiles？</p>
<blockquote>
<p>在项目的开发中，有些配置文件在开发、测试或者生产等不同环境中可能是不同的</p>
<p>例如数据库连接、redis 的配置等等</p>
<p>那如何在不同环境中自动实现配置的切换呢？Spring 提供了 profiles 机制实现切换配置文件的功能</p>
<p>Spring Profiles 允许用户根据配置文件（dev、test、prod 等）来注册 bean</p>
<p>因此当应用程序在开发中运行时，只有某些 bean 可以加载，而在 PRODUCTION 中，某些其他 bean 可以加载</p>
<p>假设要求 Swagger 文档仅适用于 QA 环境，并且禁用所有其他文档。这可以使用配置文件来完成</p>
<p>SpringBoot 使得使用配置文件非常简单</p>
</blockquote>
</li>
<li><p>如何使用 Spring Boot 实现全局异常处理</p>
<blockquote>
<p>Spring 提供了一种使用 <code>ControllerAdvice</code> 处理异常的非常有用的方法。</p>
<p>通过实现一个 <code>ControlerAdvice</code> 类，来处理控制器类抛出的所有异常</p>
</blockquote>
</li>
<li><p><strong>Spring Boot 微服务中如何实现 session 共享</strong></p>
<blockquote>
<p>在微服务中，一个完整的项目被拆分成多个不相同的独立的服务，各个服务独立部署在不同的服务器上，各自的 session 被从物理空间上隔离开了</p>
<p>但是经常需要在不同微服务之间共享 session，常见的方案就是 <code>Spring Session+Redis</code> 来实现session 共享</p>
<p>将所有微服务的 session 统一保存在 Redis 上，当各个微服务对 session 有相关的读写操作时，都去操作 Redis 上的 session</p>
<p>这样就实现了 session 共享，Spring Session 基于 Spring 中的代理过滤器实现，使得 session 的同步操作对开发人员而言是透明的，非常简便</p>
</blockquote>
</li>
<li><p>Spring Boot 中如何实现定时任务</p>
<blockquote>
<p>在 Spring Boot 中使用定时任务主要有两种不同的方式</p>
</blockquote>
<ul>
<li>使用 Spring 中的 <code>@Scheduled</code> 注解</li>
<li>使用第三方框架 Quartz</li>
</ul>
</li>
<li><p>Spring Boot 如何实现打包</p>
<ul>
<li><p>命令行</p>
<blockquote>
<p>进入项目目录在控制台输入 mvn clean package，clean 是清空已存在的项目包，package 进行打包 </p>
</blockquote>
</li>
<li><p>图形界面</p>
<blockquote>
<p>点击选项栏中的 Mavne，先点击 clean 再点击 package</p>
</blockquote>
</li>
</ul>
</li>
<li><p>Spring Boot 打成的 jar 包和普通的 jar 包有什么区别</p>
<ul>
<li><p><strong>SpringBoot 项目最终打包成的 jar 是可执行 jar，这种 jar 可以直接通过 <code>java-jarxxx.jar</code> 命令来运行</strong></p>
</li>
<li><p><strong>SpringBoot 的 jar 无法被其他项目依赖，即使依赖了也无法使用其中的类</strong></p>
<blockquote>
<p>主要还是他和普通jar的结构不同</p>
<p>普通的 jar 包，解压后直接就是包名，包里就是代码</p>
<p>而 Spring Boot 打包成的可执行 jar 解压后，在 <code>BOOT-INF\c1asses</code> 目录下才是代码，因此无法被直接引用</p>
<p><strong>如果非要引用，可以在 <code>pom.xml</code> 文件中增加配置，将 Spring Boot 项目打包成两个 jar，一个可执行，一个可引用</strong></p>
</blockquote>
</li>
</ul>
</li>
<li><p>Spring Boot 如何兼容 Spring 项目</p>
<blockquote>
<p>在启动类添加: <code>@ImportResource(locations = &#123;&quot;classpath:spring.xml&quot;&#125;)</code></p>
</blockquote>
</li>
<li><p>针对请求访问的几个组合注解</p>
<ul>
<li>@PatchMapping </li>
<li>@PostMapping </li>
<li>@GetMapping </li>
<li>@PutMapping </li>
<li>@DeleteMapping</li>
</ul>
</li>
<li><p>不同的环境的配置文件</p>
<blockquote>
<p>一般来说从开发到生产，经过开发（dev）、测试（test）、上线（prod）三个阶段</p>
<p>不同的阶段会用不同的配置</p>
<p>SpringProfiles 允许用户根据配置文件（dev、test、prod 等）来注册 bean</p>
<p>选择什么时候用什么配置</p>
</blockquote>
</li>
</ol>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://gitee.com/zcmmmm/zcmmmm">zcm</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://gitee.com/zcmmmm/zcmmmm/2022/10/27/SpringBoot%E9%9D%A2%E7%BB%8F/">https://gitee.com/zcmmmm/zcmmmm/2022/10/27/SpringBoot%E9%9D%A2%E7%BB%8F/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://gitee.com/zcmmmm/zcmmmm" target="_blank">无人深空</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/SpringBoot/">SpringBoot</a></div><div class="post_share"><div class="social-share" data-image="https://study-record-images.oss-cn-beijing.aliyuncs.com/Java/Spring/Spring.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2022/10/28/SpringCloud%E9%9D%A2%E7%BB%8F/"><img class="prev-cover" src="https://study-record-images.oss-cn-beijing.aliyuncs.com/Java/Spring/Spring.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">SpringCloud面经</div></div></a></div><div class="next-post pull-right"><a href="/2022/10/26/SpringMVC%E9%9D%A2%E7%BB%8F/"><img class="next-cover" src="https://study-record-images.oss-cn-beijing.aliyuncs.com/Java/Spring/Spring.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">SpringMVC面经</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring-Boot-%E9%9D%A2%E7%BB%8F"><span class="toc-text">Spring Boot 面经</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-Spring-Boot-%E7%AE%80%E4%BB%8B"><span class="toc-text">1.Spring Boot 简介</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-Spring-Boot-%E5%A4%9A%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="toc-text">2.Spring Boot 多数据源</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-Java-Config"><span class="toc-text">3.Java Config</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-Spring-Boot-%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7"><span class="toc-text">4.Spring Boot 的安全性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-Spring-Boot-%E7%9B%91%E8%A7%86%E5%99%A8"><span class="toc-text">5.Spring Boot 监视器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-Spring-Boot-Starter"><span class="toc-text">6.Spring Boot Starter</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-Spring-Boot-%E6%B3%A8%E8%A7%A3"><span class="toc-text">7.Spring Boot 注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E7%BB%86%E8%8A%82"><span class="toc-text">其他细节</span></a></li></ol></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2022 - 2023 By zcm</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script src="/js/categories.js?v1"></script><script src="/js/navigation.js?v1"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>